﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

using Gurucore.Framework.Core;
using Gurucore.Framework.DataAccess.Persistence.QueryLanguage;

namespace Gurucore.Framework.DataAccess.Persistence
{
	public abstract class Query<T> where T : class
	{
		protected Expression m_expFilter;
		protected Order m_order;
		protected int m_nOffset = 0;
		protected int m_nCount = 0; //all

		public virtual SubQueryOperand Yield(params ColumnOperand[] p_columns)
		{
			SqlGenerator oSqlGenerator = new SqlGenerator();

			List<string> fetchedColumns = null;
			if ((p_columns == null) || (p_columns.Length == 0))
			{
				fetchedColumns = GetColumnsList();
			}
			else
			{
				fetchedColumns = new List<string>();
				foreach (ColumnOperand column in p_columns)
				{
					fetchedColumns.Add(column.FullName);
				}
			}

			string sQuery = oSqlGenerator.GenerateListSelectQuery(this.GetQueryTarget(), m_expFilter, m_order, m_nOffset, m_nCount, fetchedColumns);
			return new SubQueryOperand(sQuery);
		}

		public virtual Aggregation Count(Expression p_exp)
		{
			return Aggregation.COUNT;
		}

		public virtual Aggregation Sum()
		{
			return Aggregation.SUM;
		}

		public virtual Aggregation Max()
		{
			return Aggregation.MAX;
		}

		public virtual Aggregation Min()
		{
			return Aggregation.MIN;
		}

		public virtual Aggregation Avg()
		{
			return Aggregation.AVG;
		}

		public virtual List<T> Select(params ColumnOperand[] p_columns)
		{
			DataAccessConfiguration oDACfg = Application.GetInstance().GetGlobalSharedObject<DataAccessConfiguration>();
			DataAccessContext oDACtx = DataAccessContext.GetDataAccessContext();

			SqlGenerator oSqlGenerator = new SqlGenerator();

			DTOTransformer transformer = GetBatchTransformer();

			List<string> fetchedColumns = null;
			if ((p_columns == null) || (p_columns.Length == 0))
			{
				fetchedColumns = GetColumnsList();
			}
			else
			{
				fetchedColumns = new List<string>();
				foreach (ColumnOperand column in p_columns)
				{
					fetchedColumns.Add(column.FullName);
				}
			}

			IDbConnection oDbConn = oDACtx.GetConnection();
			IDbCommand oDbCmd = oDACtx.GetDbCommand(oDbConn);

			oSqlGenerator.PrepareListSelectCommand(oDbCmd, this.GetQueryTarget(), m_expFilter, m_order, m_nOffset, m_nCount, fetchedColumns);

			IDataReader oDataReader = oDbCmd.ExecuteReader();

			List<T> arrDTOs = transformer.Transform<T>(oDataReader, GetSample());

			oDataReader.Close();
			oDACtx.ReturnConnection(oDbConn);

			return arrDTOs;
		}

		public virtual int Update(ColumnOperand[] p_arrColumn, Expression[] p_arrNewValue)
		{
			throw new Exception("Not implemented");
		}

		public virtual int Delete()
		{
			throw new Exception("Not implemented");
		}

		public virtual FinalizedQuery<U> Into<U>(U p_sample) where U : class
		{
			return new FinalizedQuery<U>(p_sample, this.GetQueryTarget(), m_expFilter, m_order, m_nOffset, m_nCount);
		}

		public virtual Query<T> Where(Expression p_exp)
		{
			m_expFilter = p_exp;
			return this;
		}

		public virtual Query<T> OrderBy(Expression p_exp, OrderType p_type)
		{
			m_order = new Order(p_exp, p_type);
			return this;
		}

		public virtual Query<T> Limit(int p_nOffset, int p_nCount)
		{
			m_nOffset = p_nOffset;
			m_nCount = p_nCount;

			return this;
		}

		public virtual JoinQuery<T, U> Join<U>(Query<U> p_other, Expression p_exp) where U : class
		{
			return new JoinQuery<T, U>(this, p_other, p_exp, JoinQuery<T, U>.JoinType.Inner);  //so, lost U ???
		}

		public virtual JoinQuery<T, U> LeftJoin<U>(Query<U> p_other, Expression p_exp) where U : class
		{
			return new JoinQuery<T, U>(this, p_other, p_exp, JoinQuery<T, U>.JoinType.LeftOuter);  //so, lost U ???
		}

		internal abstract string GetQueryTarget();

		internal abstract List<string> GetColumnsList();

		internal abstract T GetSample();

		internal abstract DTOTransformer GetBatchTransformer();

	}
}
